declare module 'react' {
  function forwardRef<T, P = {}>(
    render: (props: P, ref: React.Ref<T>) => React.ReactNode | null,
  ): (props: P & React.RefAttributes<T>) => React.ReactNode | null;
}

import type { ProFormInstance } from '@ant-design/pro-form';
import ProForm from '@ant-design/pro-form';
import { keys, pick } from 'lodash';
import React, { useRef, forwardRef, useImperativeHandle, useEffect } from 'react';
import useDispatcher from '../hooks/useDispatcher';
import type { Store } from 'antd/lib/form/interface';

interface IWrapperFormProps<T> extends React.PropsWithChildren {
  data: T;
  reducerName?: string;
  onBeforeUpdate?: (
    changeVal: Partial<T>,
    allVal: T,
    formRef?: React.MutableRefObject<ProFormInstance | undefined>,
  ) => Partial<T> | undefined;
  onChange?: (
    changeVal: Partial<T>,
    allVal: T,
    formRef?: React.MutableRefObject<ProFormInstance | undefined>,
  ) => void;
}

export type WrapperFormRef<T> = {
  formRef: ProFormInstance | undefined;
  update: (val: Partial<T>) => {
    type: string;
    payload: Partial<T>;
  };
};

function WrapperForm<T extends Store | undefined>(
  props: IWrapperFormProps<T>,
  ref: React.Ref<WrapperFormRef<T>>,
) {
  const { data, reducerName = 'updateData', onChange, onBeforeUpdate } = props;
  const formRef = useRef<ProFormInstance>();

  const update = useDispatcher<Partial<T>>();

  useImperativeHandle(
    ref,
    () => ({
      formRef: formRef.current,
      update: (val: Partial<T>) => update(reducerName, val),
    }),
    [formRef, update],
  );

  const onChangeable = (val: Partial<T>, allValue: T) => {
    let currentValue = pick<T>(allValue, keys(val));
    if (onBeforeUpdate) {
      const beforeUpdateVal = onBeforeUpdate?.(currentValue, allValue, formRef);
      currentValue = beforeUpdateVal || {};
    }
    update(reducerName, currentValue);
    onChange?.(val, allValue, formRef);
    update('validateUpdate', {});
    // dispatch({
    //   type: 'decoration/validateUpdate',
    //   payload: {
    //     id: data?.id,
    //   },
    // });
  };

  useEffect(() => {
    formRef.current?.validateFields();
  }, []);

  useEffect(() => {
    formRef.current?.setFieldsValue(data);
    formRef.current?.validateFields();
  }, [data]);

  return (
    data && (
      <ProForm<T>
        formRef={formRef}
        initialValues={data}
        submitter={false}
        onValuesChange={onChangeable}
      >
        {props.children}
      </ProForm>
    )
  );
}

export default forwardRef(WrapperForm);
